package mysql

import (
	"database/sql"
	"sync"
	"time"

	"gitee.com/zibianqu/fyzdb/lib"
	"gitee.com/zibianqu/fyzdb/lib/snowid"
)

type SessionModel struct {
	SessionId  int64
	StartTime  int64
	Connection string
	Tx         *sql.Tx
	Builder    *Builder
}

// 会话列表
var SessionList sync.Map

// 获取会话
func Session(sessionIds ...int64) *SessionModel {
	defer CleanSession()
	sessionId := int64(0)
	for _, sessionId = range sessionIds {
		val, ok := SessionList.Load(sessionId)
		if ok {
			return val.(*SessionModel)
		}
	}
	sessionId = snowid.Unique()
	s := &SessionModel{
		SessionId:  sessionId,
		Connection: "default",
		// 保证在使用的时候都是新的构建器
		// Builder:   MakeBuilder(sessionId),
		StartTime: time.Now().Unix(),
	}
	SessionList.Store(sessionId, s)
	return s
}

func CleanSession() {
	// 并发情况下读写跟迭代同时进行会报错
	// 先获取，然后在去操作
	sIds := make([]int64, 0)
	SessionList.Range(func(key any, value any) bool {
		session := value.(*SessionModel)
		// 超过1小时
		if session.StartTime+int64(time.Second)*60*60 < time.Now().Unix() {
			sIds = append(sIds, key.(int64))
		}
		return true
	})
	for _, id := range sIds {
		SessionList.Delete(id)
	}
}

func MakeBuilder(sessionId int64) *Builder {
	return &Builder{
		SessionId:  sessionId,
		connection: "",
		logSql:     "",
		log:        false,
		mapping:    mapping,
	}
}

func (s *SessionModel) SetConnection(connection string) *SessionModel {
	s.Connection = connection
	s.Builder = &Builder{
		SessionId:  s.SessionId,
		connection: connection,
		logSql:     "",
		log:        false,
		mapping:    mapping,
	}
	SessionList.Store(s.SessionId, s)
	// s.Builder.connection = connection
	return s
}

func (s *SessionModel) GetSessionId() int64 {
	return s.SessionId
}

func (s *SessionModel) BeginTrans(connection ...string) *SessionModel {
	for _, s.Connection = range connection {
	}
	db := Mysql().GetDb(s.Connection)
	tx, err := db.Begin()

	lib.ThrowError(err)
	// fmt.Println("开启事务", s.SessionId, tx)
	s.Tx = tx
	return s
}

func (s *SessionModel) Commit() error {
	err := s.Tx.Commit()
	s.Tx = nil
	SessionList.Delete(s.SessionId)
	return err
}

func (s *SessionModel) Rollback() error {
	err := s.Tx.Rollback()
	s.Tx = nil
	SessionList.Delete(s.SessionId)
	return err
}

func (s *SessionModel) DelSession(sessionId int64) {
	SessionList.Delete(s.SessionId)
}
